package com.slwu.handler;


import com.slwu.common.RESP;
import com.slwu.exception.CommonException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.net.URISyntaxException;
import java.nio.file.AccessDeniedException;
import java.util.List;
import java.util.UUID;

/**
 * @author wushaolin
 */
@RestControllerAdvice
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionHandler {

    private   final Logger log = LoggerFactory.getLogger(this.getClass());

    @ExceptionHandler({CommonException.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handleException(CommonException e) {
        RESP<String> result = new RESP<>();
        result.setCode(e.getHttpStatus().value());
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        result.setMsg(e.getMessage());
        result.setErrType("E");
        result.setData(e.getMessage());
        return result;
    }

    @ExceptionHandler({BindException.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handleBindException(BindException e) {
        RESP<String> result = new RESP<>();
        result.setCode(500);
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        List<ObjectError> allErrors = e.getAllErrors();
        StringBuilder builder = new StringBuilder();
        StringBuilder builder1 = new StringBuilder();
        allErrors.forEach((objectError) -> {
            String string = objectError.getClass().toString();
            if (string.contains("ViolationFieldError")) {
                builder1.append(objectError.getDefaultMessage());
            } else {
                if (objectError instanceof FieldError) {
                    builder.append(" ").append(((FieldError) objectError).getField());
                }
            }
        });
        String message = StringUtils.isNotBlank(builder1.toString()) ? builder1.toString() : (builder + "无效");
        result.setMsg(message);
        result.setErrType("E");
        result.setData(message);
        return result;
    }

    @ExceptionHandler({URISyntaxException.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handleURISyntaxException(URISyntaxException e) {
        RESP<String> result = new RESP<>();
        result.setCode(500);
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        result.setMsg("非法字符");
        result.setErrType("E");
        return result;
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handleBindException(MethodArgumentNotValidException e) {
        RESP<String> result = new RESP<>();
        result.setCode(500);
        FieldError fieldError = e.getBindingResult().getFieldError();
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        assert fieldError != null;
        result.setMsg(fieldError.getDefaultMessage());
        result.setErrType("E");
        result.setData(fieldError.getDefaultMessage());
        return result;
    }

    @ExceptionHandler({Exception.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handleException(Exception e) {
        RESP<String> result = new RESP<>();
        result.setCode(500);
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ,e [{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        result.setMsg("服务器出小差了");
        return result;
    }

    @ExceptionHandler({NullPointerException.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handleNullPointerException(NullPointerException e) {
        RESP<String> result = new RESP<>();
        result.setCode(500);
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ,e [{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        result.setMsg("服务器出小差了");
        return result;
    }

    @ExceptionHandler({HttpMessageNotReadableException.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        RESP<String> result = new RESP<>();
        result.setCode(400);
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ,e [{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        result.setMsg(this.getMessage(e.getMessage()));
        return result;
    }

    @ExceptionHandler({AccessDeniedException.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handleAccessDeniedException() {
        RESP<String> result = new RESP<>();
        result.setCode(403);
        result.setMsg("没有权限访问该资源");
        return result;
    }

    @ExceptionHandler({IllegalArgumentException.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handleIllegalArgumentException(IllegalArgumentException e) {
        RESP<String> result = new RESP<>();
        result.setCode(500);
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ,e [{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        result.setMsg(e.getMessage());
        return result;
    }

    @ExceptionHandler({MissingServletRequestParameterException.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        this.log.error(e.getMessage(), e);
        RESP<String> result = new RESP<>();
        result.setCode(400);
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ,e [{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        result.setMsg(this.getMessage(e.getMessage()));
        return result;
    }

    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    @ResponseStatus(HttpStatus.OK)
    public RESP<String> handlerHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        this.log.error(e.getMessage(), e);
        RESP<String> result = new RESP<>();
        result.setCode(400);
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ,e [{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        result.setMsg(this.getMessage(e.getMessage()));
        return result;
    }

    @ExceptionHandler({NoHandlerFoundException.class})
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public RESP<String> handlerNoFoundException(Exception e) {
        this.log.error(e.getMessage(), e);
        RESP<String> result = new RESP<>();
        result.setCode(404);
        String id = UUID.randomUUID().toString();
        this.log.error("id[{}] ,msg[{}] ,e [{}] ", id, e.getMessage(), e);
        result.setExcId(id);
        result.setMsg("路径不存在，请检查路径是否正确");
        return result;
    }

    public String getMessage(String message) {
        if (null == message) {
            return "";
        } else if (message.length() > 100) {
            return message.substring(0, 99);
        } else {
            return message;
        }
    }

}
